use core::{ffi::c_void, mem::size_of, primitive, ptr::null, result::Result};

use crate::{irq::*, mem::rt_free, println, rt_extern::*, scheduler::*, timer::*};

use core::cell::RefCell;

use alloc::{collections::{BTreeSet, LinkedList}, string::String, sync::Arc, vec::Vec};

use crate::mem::rt_malloc;

pub const RT_THREAD_PRIORITY_MAX: usize = 32;
pub static mut RT_THREAD_PRIORITY_TABLE: &mut [LinkedList<Arc<RefCell<Thread>>>] = &mut[THREAD_LIST; RT_THREAD_PRIORITY_MAX];
pub static mut RT_THREAD_LIST: Vec<Arc<RefCell<Thread>>> = Vec::new();
pub static mut RT_THREAD_SUSPEND_LIST: Vec<Arc<RefCell<Thread>>> = Vec::new();
pub static mut RT_THREAD_DEFUNCT: Vec<Arc<RefCell<Thread>>> = Vec::new();

const fn thread_list_new() -> LinkedList<Arc<RefCell<Thread>>> {
    LinkedList::new()
} 

const THREAD_LIST: LinkedList<Arc<RefCell<Thread>>> = thread_list_new();

fn thread_len_of_priority_table(prio: usize) -> usize {
    unsafe {
        RT_THREAD_PRIORITY_TABLE[prio].len()
    }
}

fn append_suspend_list(thread: Arc<RefCell<Thread>>) {
    unsafe {
        RT_THREAD_SUSPEND_LIST.push(thread);
    }
}

fn remove_from_suspend_list(thread: &Arc<RefCell<Thread>>) -> Result<(), RtErrCode> {
    unsafe {
        let mut ind = -1i32;
        for (i, t) in RT_THREAD_SUSPEND_LIST.iter().enumerate() {
            if t == thread {
                ind = i as i32;
                break;
            }
        }

        if ind < 0 {
            return Err(RtErrCode::RtEinval)
        }

        RT_THREAD_SUSPEND_LIST.swap_remove(ind as usize);
    }

    Ok(())
}

#[derive(Debug, PartialEq)]
enum ThreadState {
    RtThreadInit,
    RtThreadReady,
    RtThreadSuspend,
    RtThreadRunning,
    RtThreadBlock,
    RtThreadClose
}

#[derive(Debug, PartialEq)]
#[repr(C)]
pub struct Thread {
    name: String,

    sp: usize,
    entry: *const c_void,
    parameter: *const c_void,
    stack_addr: *mut u8,
    stack_size: usize,

    // State
    stat: ThreadState,

    // 优先级
    current_priority: usize,
    init_priority: usize,

    // 时间片
    init_tick: usize,
    remaining_tick: usize,

    // 定时器
    pub timer: Arc<RefCell<RtTimer>>,

    // 错误码
    err: Result<(), RtErrCode>,
}

#[no_mangle]
pub fn rt_thread_create(
    name: String,
    entry: *const c_void, 
    parameter: *const c_void, 
    stack_size: usize, 
    priority: usize, 
    tick: usize
) -> Option<Arc<RefCell<Thread>>> {
    let saddr = rt_malloc(8192);
    if saddr.is_null() {
        return None;
    }
    let t = Arc::new(RefCell::new(Thread::init(name, entry, parameter, saddr as *mut u8, stack_size, priority, tick)));

    let ptr_th = Arc::into_raw(t.clone());
    t.borrow_mut().timer.borrow_mut().set_parameter(ptr_th as *const c_void);
    drop( unsafe { Arc::from_raw(ptr_th) }); // 减去一个计数
    Some(t)
}


impl Thread {

    pub fn init(
        name: String,
        entry: *const c_void, 
        parameter: *const c_void, 
        stack_start:* mut u8, 
        stack_size: usize, 
        priority: usize, 
        tick: usize
    ) -> Self {
        assert!(priority < RT_THREAD_PRIORITY_MAX);

        let exit_entry = rt_thread_exit as *const c_void;

        let mut t:Thread = Thread {
            name: name.clone(),

            entry,
            parameter,
            stack_addr: stack_start,
            stack_size,
            sp: 0,

            stat: ThreadState::RtThreadInit,

            current_priority: priority,
            init_priority: priority,

            init_tick: tick,
            remaining_tick: tick,

            err: Ok(()),

            timer: rt_timer_new(name, Some(rt_thread_timeout), null(), 0, TimerFlag::RtTimerFlagOneShot)
        };
    
        unsafe {
            t.sp = rt_hw_stack_init(t.entry, t.parameter, t.stack_addr.offset(stack_size as isize - size_of::<usize>() as isize), exit_entry) as usize;
        }
        t
    }

    pub fn name(&self) -> String {
        self.name.clone()
    }

    pub fn stack_addr(&self) -> usize {
        return self.stack_addr as usize;
    }

    pub fn sp_ptr(&self) -> *const usize {
        let p: *const usize =  &self.sp;
        p 
    }

    pub fn is_running(&self) -> bool {
        self.stat == ThreadState::RtThreadRunning
    }

    pub fn is_ready(&self) -> bool {
        self.stat == ThreadState::RtThreadReady
    }

    pub fn is_suspend(&self) -> bool {
        self.stat == ThreadState::RtThreadSuspend
    }

    pub fn suspend(&mut self) {
        self.stat = ThreadState::RtThreadSuspend;
    }

    pub fn running(&mut self) {
        self.stat = ThreadState::RtThreadRunning;
    }

    pub fn ready(&mut self) {
        self.stat = ThreadState::RtThreadReady;
    }

    pub fn close(&mut self) {
        self.stat = ThreadState::RtThreadClose;
    }

    pub fn priority(&self) -> usize {
        self.current_priority
    }

    pub fn tick_minus(&mut self, t: usize) {
        self.remaining_tick -= t;
    }

    pub fn tick_run_out(&self) -> bool {
        self.remaining_tick == 0
    }

    pub fn remaining_tick(&self) -> usize {
        self.remaining_tick
    }

    pub fn remaining_tick_reset(&mut self) {
        self.remaining_tick = self.init_tick;
    }

    pub fn set_err(&mut self, err: Result<(), RtErrCode>) {
        self.err = err
    }

    pub fn err(&self) -> Result<(), RtErrCode> {
        self.err
    }

    pub fn timer_stop(&mut self) {
        rt_timer_stop(self.timer.clone()).unwrap_or_else(|_e| ());
    }

    pub fn timer_start(&mut self) {
        rt_timer_start(self.timer.clone());
    }

    pub fn timer_set(&mut self) {}
}

impl Drop for Thread {
    fn drop(&mut self) {
        rt_free(self.stack_addr as *mut c_void);
        println!("remove thread = {:?}!", self.name);
    }
}

pub fn rt_thread_exit() {
    let thread = get_cur_thread().unwrap();

    let level = unsafe { rt_hw_interrupt_disable() };

    remove_thread(&thread); // 从list中去除

    thread.borrow_mut().close(); // 设置状态

    rt_timer_detach(&(thread.borrow_mut().timer)); 

    //push_defunct_list(thread); // 加入至待清理列表

    unsafe { rt_hw_interrupt_enable(level) };

    println!("ref cnt {}", Arc::strong_count(&thread));
    
    drop_cur_thread(); // cur_thread 设为NULL

    drop(thread); // 直接清理
    
    rt_sys_scheduler_start();
    
}

pub fn pop_prio_thread(pri: usize) -> Option<Arc<RefCell<Thread>>> {
    unsafe{RT_THREAD_PRIORITY_TABLE[pri].pop_front()}
}

pub fn push_thread(t: Arc<RefCell<Thread>>) {
    unsafe {
        RT_THREAD_LIST.push(t.clone());
    }
}

pub fn remove_thread(t: &Arc<RefCell<Thread>>) {
    unsafe {
        let mut index = usize::MAX;
        for (ind, thread) in RT_THREAD_LIST.iter().enumerate() {
            if *thread == *t {
                index = ind;
            }
        }
        assert!(index != usize::MAX);
        RT_THREAD_LIST.swap_remove(index);
    }
}

pub fn push_prio_table(t: Arc<RefCell<Thread>>) {
    let pri = t.borrow().priority();
    t.borrow_mut().ready();
    unsafe {
        RT_THREAD_PRIORITY_TABLE[pri].push_back(t.clone());
    }
}

pub fn len_defunct_list() -> usize {
    unsafe {
        RT_THREAD_DEFUNCT.len()
    }
}

pub fn push_defunct_list(t: Arc<RefCell<Thread>>) {
    unsafe {
        RT_THREAD_DEFUNCT.push(t);
    }
}

pub fn pop_defunct_list() -> Option<Arc<RefCell<Thread>>> {
    unsafe {
        RT_THREAD_DEFUNCT.pop()
    }
}

pub fn print_thread_table() {
    for i in 0..RT_THREAD_PRIORITY_MAX {
        unsafe {
            if ! RT_THREAD_PRIORITY_TABLE[i].is_empty() {
                println!("\npriority = {}, len = {}", i, RT_THREAD_PRIORITY_TABLE[i].len());
                for th in &RT_THREAD_PRIORITY_TABLE[i] {
                    println!("{:?}", *th);
                }
            }
        }
    }
}

pub fn rt_thread_timeout(parameter: *const c_void) {
    let thread = unsafe{ Arc::from_raw(parameter as *mut RefCell<Thread>) };
    unsafe { Arc::increment_strong_count(parameter) };

    thread.borrow_mut().set_err(Err(RtErrCode::RtEtimeout));

    rt_thread_resume(thread);

    rt_schedule();

}

pub fn rt_thread_resume(thread: Arc<RefCell<Thread>>) {
    let level = unsafe { rt_hw_interrupt_disable() };

    if let Ok(_) = remove_from_suspend_list(&thread) {
        // println!("remove from suspend_list ok!");
    } else {
        println!("not in suspend!");
    }

    rt_timer_stop(thread.borrow_mut().timer.clone()).unwrap_or(());

    push_prio_table(thread);

    unsafe { rt_hw_interrupt_enable(level) };
}

#[no_mangle]
pub fn rt_thread_delay(tick: usize) {
    rt_thread_sleep(tick)
}

pub fn rt_thread_suspend(thread: Arc<RefCell<Thread>>) -> Result<(), RtErrCode> {
    if !thread.borrow().is_ready() && !thread.borrow().is_running() {
        return Err(RtErrCode::RtError);
    }

    let level = unsafe { rt_hw_interrupt_disable() };

    thread.borrow_mut().suspend();

    thread.borrow_mut().timer_stop();
    
    append_suspend_list(thread);
    
    unsafe{ rt_hw_interrupt_enable(level) };

    Ok(())
}

#[no_mangle]
pub fn rt_thread_sleep(tick: usize) {
    let level = unsafe { rt_hw_interrupt_disable() }; 

    let thread = get_cur_thread().unwrap();

    rt_thread_suspend(thread.clone()).unwrap_or_else(|e| {
        println!("{}, thread not running or ready!", e);
    });

    thread.borrow_mut().timer.borrow_mut().set_tick(tick);

    thread.borrow_mut().timer_start();

    // println!("cnt = {}", Arc::strong_count(&thread));
    drop(thread); // 减少Arc计数

    unsafe{ rt_hw_interrupt_enable(level) };

    rt_schedule();
}

#[no_mangle]
pub fn rt_thread_startup(thread: Arc<RefCell<Thread>>) {
    push_thread(thread.clone());

    push_prio_table(thread);

    if get_cur_thread().is_some() {
        rt_schedule();
    }
}

/// 待完成
#[no_mangle]
pub fn rt_thread_yield() {
    let level = unsafe{rt_hw_interrupt_disable()};

    let cur_thread = get_cur_thread().unwrap(); 
    let t = cur_thread.borrow(); 
    if thread_len_of_priority_table(t.priority()) != 0 {
        unsafe{
            rt_hw_interrupt_enable(level)
        }
        rt_schedule();
        return;
    }
    unsafe{
        rt_hw_interrupt_enable(level)
    }
}

